package com.prj.ufdm.auth.security;

import java.io.IOException;
import java.util.Collection;
import java.util.Date;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import com.prj.ufdm.auth.bpo._impl.SysFunctionBPOImpl;
import com.prj.ufdm.auth.bpo._impl.SysUserBPOImpl;
import com.prj.ufdm.auth.enums.AuthRetCodeEnum;
import com.prj.ufdm.auth.enums.ConstantEnum;
import com.prj.ufdm.auth.model.SysUser;
import com.prj.ufdm.core.util.UfdmDateUtil;

/**  
 * Token 验证过滤器 
 * @author 胡义振  
 * @date 2018年3月22日  
*/
public class TokenAuthentication  extends AbstractAuthenticationProcessingFilter {

	SysUserBPOImpl sysUserBPOImpl;
	
	SysFunctionBPOImpl sysFunctionBPOImpl;
	
    private String TOKEN_VALID_MINUTES;
	
	public TokenAuthentication(String defaultFilterProcessesUrl,SysUserBPOImpl sysUserBPOImpl,SysFunctionBPOImpl sysFunctionBPOImpl,TokenAuthenticationSuccess tokenAuthenticationSuccess ,TokenAuthenticationFailure tokenAuthFailureHandle,String TOKEN_VALID_MINUTES) {
		super(defaultFilterProcessesUrl);
		super.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(defaultFilterProcessesUrl));
		super.setAuthenticationManager(new AuthenticationManager() {
			@Override
			public Authentication authenticate(Authentication authentication) throws AuthenticationException {
				return authentication;
			}
		});
		// 验证成功
		setAuthenticationSuccessHandler(tokenAuthenticationSuccess);
		// 验证失败
		setAuthenticationFailureHandler(tokenAuthFailureHandle);
		this.sysUserBPOImpl = sysUserBPOImpl;
		this.sysFunctionBPOImpl = sysFunctionBPOImpl;
		this.TOKEN_VALID_MINUTES = TOKEN_VALID_MINUTES;
	}

	/**
	 * Token 验证
	 */
	@Override
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
		AbstractAuthenticationToken userAuthenticationToken = null;
		request.setAttribute(ConstantEnum.TOKEN_FILTER_APPLIED.getKey(), Boolean.TRUE);
		if(
				(request.getHeader(ConstantEnum.HEADER_SECURITY_TOKEN.getKey())!=null && !"".equals(request.getHeader(ConstantEnum.HEADER_SECURITY_TOKEN.getKey())))
				||
				request.getParameter(ConstantEnum.HEADER_SECURITY_TOKEN.getKey())!=null
				)
		{
			String token = request.getHeader(ConstantEnum.HEADER_SECURITY_TOKEN.getKey());
			if(token==null || "".equals(token)) {
				token = request.getParameter(ConstantEnum.HEADER_SECURITY_TOKEN.getKey());
			}
			SysUser sysUser = null;
			try {
			    sysUser = sysUserBPOImpl.doGetSysUserByToken(token);
			}
			catch(Exception er) {
				throw new AuthenticationServiceException(AuthRetCodeEnum.RET_CODE_0101006.getCode());
			}
			if(sysUser!=null) {
				
				// 判断TOKEN是否失效
				int tokenValieMinutes = 30;
				try {
					tokenValieMinutes = Integer.parseInt(TOKEN_VALID_MINUTES);
				}
				catch(Exception er) {
					
				}
				Date tokenCreateTime = UfdmDateUtil.stringToDate(sysUser.getTokenCreateTime(),"yyyy-MM-dd HH:mm:ss");
				int tokenValidMinutes = UfdmDateUtil.getBetweenMinutes(tokenCreateTime,new Date());
				if(tokenValidMinutes > tokenValieMinutes) {
					throw new AuthenticationServiceException(AuthRetCodeEnum.RET_CODE_0101009.getCode());
				}
				
				// 设置用户的权限
				Collection<GrantedAuthority> grantedAuthorities = null;
				try {
				    grantedAuthorities = sysFunctionBPOImpl.doGetGantedAuthoritiestByUserId(sysUser.getId());
				}
				catch(Exception er) {
					throw new AuthenticationServiceException(AuthRetCodeEnum.RET_CODE_0101006.getCode());
				}
				sysUser.setGrantedAuthorities(grantedAuthorities);
				userAuthenticationToken = new UsernamePasswordAuthenticationToken(sysUser, sysUser.getPassword(),sysUser.getAuthorities());
			}
			else {
				throw new AuthenticationServiceException(AuthRetCodeEnum.RET_CODE_0101005.getCode());
			}
		}
		else {
			throw new AuthenticationServiceException(AuthRetCodeEnum.RET_CODE_0101008.getCode());
		}
		return userAuthenticationToken;
	}

	
	@Override
	public void doFilter(ServletRequest req, ServletResponse res,FilterChain chain) throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;
		if (request.getAttribute(ConstantEnum.TOKEN_FILTER_APPLIED.getKey()) != null) {
			chain.doFilter(request, response);
		} else {
			super.doFilter(req, res, chain);
		}
	}
}

